package com.hb.B_面向对象.C_数据类

/**
 * 数据类的作用：使用类来封装数据，类似于Java中的DTO的概念。Java中很繁琐。。。
 * kotlin中引用了data class来表示
 */
fun main() {
    //Bird8的属性可变
    val b1 = Bird8(20.0, 1, "blue")
    val b2=b1;
    b2.age=2;

    //浅拷贝 copy。其中weight被声明为val不可变
    val b3 = b1.copy(weight = 30.0)
    println(b3.weight)

    //componentN的理解
    val b4 = Bird8(20.0, 1, "blue")
    //将类的属性绑定到相应的变量上却不是很熟悉
//    val age = b4.age
//    val weight = b4.weight
//    val color = b4.color

    //kotlin进阶的写法
    val (weight,age,color)=b4
    println(weight)
    println(age)
    println(color)

    //字符串的解构
    var bridInfo:String="20.0,1,blue"
    val (weight2,age2,color2)=bridInfo.split(",")
    println(weight2)
    println(age2)
    println(color2)

    /**
     * 数组的解构：Kotlin对于数组的解构也有一定的限制，在数组中它默认最多允许赋值5个变量
     * 因为若是变量过多，效果反而会适得其反，因为到后期你都搞不清楚哪个值要赋值给哪个变量了
     * 所以一定要合理地使用这一特性
     */

    /**
     * 除了数组支持解构外，kotlin也提供了其他常用的数据类型，让使用者不必主动声明这些数据类型
     * 他们分别是 Pair 和 Triple.其中Pair是二元组，可以理解Wie这个数据类中有两个属性；Triple是三元组
     * 对应的则是3个属性，可以去看看他们的源码,可以发现Pair和Triple都是数据类型，他们的属性可以是
     * 任意类型，我们可以按照属性的顺序来获取对应的属性的值。
     *
     * 数据类型中的解构基于 componentN 函数，如果自己不声明componentN函数，那么就会默认根据主
     * 构造函数的参数来生成具体个数的componentN函数，与从构造函数的参数无关
     */
    val pair = Pair(20.0, 1)
    val triple = Triple(20.0, 1, "blue")
    //利用属性的顺序获取值
    var weightP = pair.first
    var ageP = pair.second

    var weightT = triple.first
    var ageT = triple.second
    var colorT = triple.third

    //当然我们也可以利用解构
    val (weightP1,ageP1)=pair
    val (weightT1,ageT1,colorT1)=triple
}

/**
 * 将这个数据类反编译之后，我们还发现两个特别的方法。copy()和componentN()
 *
 * 数据类的约定与使用：
 *  1. 数据类必须拥有一个构造方法，该方法至少包含一个参数，一个没有数据的数据类是没有任何用处的
 *  2. 与普通的类不同，数据类的构造方法的参数强制使用var或者val进行声明
 *  3. data class之前不能用abstract、open、sealed或者inner进行修饰
 *  4. 数据类可以实现接口也可以继承类。
 *  5. 把数据流和when表达式结合在一起，就可以提供更强大的业务组织和表达能力
 *
 *  copy、componentN与解构
 *
 *  copy方法的主要作用就是帮我们从已有的数据类对象中拷贝一个新的数据类对象。当然你可以传入相应的
 *  参数来生成不同的对象。但同时我们发现，在copy的执行过程中，若你未指定具体的属性的值，那么新生成的
 *  对象的属性值将使用被copy对象的属性值，这便是我们平常所说的浅拷贝。
 *
 *  实际上copy更像是一种语法糖，加入我们的类时不可变的，属性时不可修改的，那么我们只能通过copy来
 *  帮我们基于原有对象生成一个新的对象。
 *
 *  copy更像是提供了一种简洁的方式帮我们复制一个对象，但它是一种浅拷贝的方式。所以在使用copy的时候要
 *  注意使用的场景。因为数据类型的属性可以被修饰为var,这便不能保证不会出现引用修改的问题。
 *
 *  componentN 方法：简单来说，componentN可以理解为类属性的值，其中N代表属性的顺序，比如component1代表
 *  第一个属性的值，component3代表第三个属性的值。这样设计的好处：我们或多或少的知道怎么讲属性绑定到类上
 *  但是如何将类的属性绑定到相应的变量上却不是很熟悉。
 *
 *
 */
data class Bird8(val weight:Double,var age:Int,var color:String)